package service

import (
	"bgs/cache/redisImp"
	"bgs/conf"
	"bgs/db"
	sqlc "bgs/db/sqlc"
	"bgs/grpc/client"
	"bgs/grpc/imp/enums"
	"bgs/service/model"
	"bgs/util"
	"bgs/wxp/mina"
	"context"
	"encoding/json"
	"fmt"
	"time"

	"go.uber.org/zap"
)

// EnforcementServiceImp enforcement bizlogic
type EnforcementServiceImp struct {
	dao        *db.PgDao
	slog       *zap.SugaredLogger
	wechatVars *conf.WechatSection
	vars       *conf.VarsSection
	proxy      *client.GrpcClientProxy
	cacher     *cache.Adapter
}

// NewEnforcementService initialization
func NewEnforcementService(
	pgdao *db.PgDao,
	slog *zap.SugaredLogger,
	wechatVars *conf.WechatSection,
	vars *conf.VarsSection,
	proxy *client.GrpcClientProxy,
	adp *cache.Adapter,
) *EnforcementServiceImp {
	return &EnforcementServiceImp{
		dao:        pgdao,
		slog:       slog.With("module", "EnforcementService"),
		wechatVars: wechatVars,
		vars:       vars,
		proxy:      proxy,
		cacher:     adp,
	}
}

// AfterOrderPreparedParam DoAfterOrderPrepared param
type AfterOrderPreparedParam struct {
	OrderSerialNumber string
	Prepared          time.Time
	PickupCode        string
	PickupAddress     string
	PickupDeadline    string
}

// DoAfterOrderPrepared after prepare do (被动,依赖远端消息)
func (s *EnforcementServiceImp) DoAfterOrderPrepared(ctx context.Context, q *sqlc.Queries, p AfterOrderPreparedParam) (err error) {
	slog := util.NewContextLogger(ctx, s.slog)

	enforcment, err := q.GetEnforcementByOrderSerialNumber(ctx, p.OrderSerialNumber)
	if err != nil {
		return err
	}
	slog.Infof("1、获取本地履约单 ok")
	order, err := q.GetOrder(ctx, enforcment.OrderID)
	if err != nil {
		return err
	}
	slog.Infof("2、获取订单 ok")

	if order.OrderStatus != string(enums.OrderStatusPayed) {
		return fmt.Errorf("订单状态不匹配: %s,应为payed", order.OrderStatus)
	}

	order, err = q.FlowOrderFromPayedToPrepared(ctx, enforcment.OrderID)
	if err != nil {
		return err
	}
	slog.Infof("3、订单流转到已备货 ok")
	enforcment, err = q.UpdateOrderEnforcementForPreparedByInventory(ctx, sqlc.UpdateOrderEnforcementForPreparedByInventoryParams{
		ID:             enforcment.ID,
		Prepared:       sqlc.NTimeFromTime(p.Prepared),
		PickupCode:     sqlc.NSFromString(p.PickupCode),
		PickupAddress:  sqlc.NSFromString(p.PickupAddress),
		PickupDeadline: sqlc.NSFromString(p.PickupDeadline),
	})
	if err != nil {
		return err
	}
	slog.Info("4、更新本地履约单信息 ok")

	return
}

// AfterOrderDeliveredParam DoAfterOrderDelivered param
type AfterOrderDeliveredParam struct {
	OrderSerialNumber string
	Delivered         time.Time
	Platform          string
	PlatformOrderNum  string
}

// DoAfterOrderDelivered after deliver do (被动,依赖远端消息)
func (s *EnforcementServiceImp) DoAfterOrderDelivered(ctx context.Context, q *sqlc.Queries, p AfterOrderDeliveredParam) (err error) {
	slog := util.NewContextLogger(ctx, s.slog)

	enforcment, err := q.GetEnforcementByOrderSerialNumber(ctx, p.OrderSerialNumber)
	if err != nil {
		return err
	}
	slog.Infof("1、获取本地履约单 ok")
	order, err := q.GetOrder(ctx, enforcment.OrderID)
	if err != nil {
		return err
	}
	slog.Infof("2、获取订单 ok")

	if order.OrderStatus != string(enums.OrderStatusPayed) {
		return fmt.Errorf("订单状态不匹配: %s,应为payed", order.OrderStatus)
	}

	order, err = q.FlowOrderFromPayedToDelivered(ctx, enforcment.OrderID)
	if err != nil {
		return err
	}
	slog.Infof("3、订单流转到已发货 ok")

	shippingLogisticsInfo := model.LogisticsInfo{
		Platform:         p.Platform,
		PlatformOrderNum: p.PlatformOrderNum,
	}
	bytesOfShippingLogisticsInfo, err := json.Marshal(shippingLogisticsInfo)
	if err != nil {
		return err
	}
	enforcment, err = q.UpdateOrderEnforcementForDeliveredByInventory(ctx, sqlc.UpdateOrderEnforcementForDeliveredByInventoryParams{
		ID:                    enforcment.ID,
		Delivered:             sqlc.NTimeFromTime(p.Delivered),
		ShippingLogisticsInfo: sqlc.NRawMessageFromRawMessage(json.RawMessage(bytesOfShippingLogisticsInfo)),
	})
	if err != nil {
		return err
	}
	slog.Info("4、更新本地履约单信息 ok")

	return
}

// DoAfterOrderReceived after received do (主动,发送远端消息给仓库)
func (s *EnforcementServiceImp) GetDeliverNumber(ctx context.Context, q *sqlc.Queries, orderSerialNumber string) (deliverNumber string, err error) {
	slog := util.NewContextLogger(ctx, s.slog)

	enforcment, err := q.GetEnforcementByOrderSerialNumber(ctx, orderSerialNumber)
	if err != nil {
		return
	}
	slog.Infof("1、获取本地履约单 ok")
	deliverNumber = enforcment.DeliveryNumber.String
	return
}

// GenOrderDeliveredNotifyMessage (主动,生成微信小程序消息=>订单已发货)
func (s *EnforcementServiceImp) GenOrderDeliveredNotifyMessage(ctx context.Context, q *sqlc.Queries, orderSerialNumber string) (ret mina.SendNotifyParam, err error) {
	slog := util.NewContextLogger(ctx, s.slog)

	order, err := q.GetOrderBySerialNumber(ctx, orderSerialNumber)
	if err != nil {
		return
	}
	slog.Info("1、读取订单 ok")
	orderExtInfo := &model.OrderExtInfo{}
	err = json.Unmarshal(order.ExtInfo, orderExtInfo)
	if err != nil {
		err = fmt.Errorf("unmarshal order ext_info失败:%s", err.Error())
		return
	}
	brandName := orderExtInfo.BrandName
	productNamesDesc := util.JoinString(util.MapToString(util.ToGenericSlice(orderExtInfo.Details), func(v interface{}) string {
		val := v.(*model.OrderDetailInExtInfo)
		return fmt.Sprintf("%sx%d", val.ProductName, val.Quantity)
	}), ";")

	ret.Page = fmt.Sprintf("package-order/pages/order-detail/index?orderNumber=%s", orderSerialNumber)
	ret.TemplateID = s.wechatVars.Tp524 //"1YqnVgeLO_joz9cT1j0mAAAFbjZ2KA6fFL3uBVBorB8"
	ret.UserOpenID = order.UserOpenID
	ret.MinaState = s.wechatVars.MinaState
	ret.Content = map[string]map[string]interface{}{
		"character_string6": {"value": fmt.Sprintf("****%s", util.RightString(orderSerialNumber, 4))},
		"thing14":           {"value": brandName},
		"thing17":           {"value": productNamesDesc},
		"phrase2":           {"value": "已发货"},
		"thing5":            {"value": "您的订单已发货，请留意~"},
	}

	slog.Infof("生成微信小程序消息=>订单已发货 ok")

	return
}

// NotifyOrderPrepared (主动,生成微信小程序消息=>订单已备货)
func (s *EnforcementServiceImp) GenOrderPreparedNotifyMessage(ctx context.Context, q *sqlc.Queries, orderSerialNumber string) (ret mina.SendNotifyParam, err error) {
	slog := util.NewContextLogger(ctx, s.slog)

	order, err := q.GetOrderBySerialNumber(ctx, orderSerialNumber)
	if err != nil {
		return
	}
	slog.Info("1、读取订单 ok")
	orderExtInfo := &model.OrderExtInfo{}
	err = json.Unmarshal(order.ExtInfo, orderExtInfo)
	if err != nil {
		err = fmt.Errorf("unmarshal order ext_info失败:%s", err.Error())
		return
	}
	warehouseName := orderExtInfo.WarehouseInfo.Name
	enforcement, err := q.GetEnforcementByOrderSerialNumber(ctx, orderSerialNumber)
	if err != nil {
		return
	}
	slog.Info("2、读取履约单 ok")
	ret.Page = fmt.Sprintf("package-order/pages/order-detail/index?orderNumber=%s", orderSerialNumber)
	ret.TemplateID = s.wechatVars.Tp4959  //"vOtbeyN0rEvR42TfagkYU0nByJ9dEG4tLymMFXNZgxU"
	ret.UserOpenID = order.UserOpenID
	ret.MinaState = s.wechatVars.MinaState
	ret.Content = map[string]map[string]interface{}{
		"character_string2": {"value": fmt.Sprintf("****%s", util.RightString(orderSerialNumber, 4))},
		"thing1":            {"value": warehouseName},
		"character_string4": {"value": enforcement.PickupCode.String},
		"thing5":            {"value": "您预定的商品已到货，请凭提货码到店自取！"},
	}

	slog.Infof("生成微信小程序消息=>订单已备货 ok")

	return
}
